package com.smartalarmclock.Model;

import java.util.HashSet;
import java.util.Set;

import android.content.Context;

import com.smartalarmclock.Model.Exceptions.DataEntityDoesNotExistException;
import com.smartalarmclock.Model.ITimeFrame.TimeInWeek;

public final class RulesItemFactory implements IReferencingDataEntityFactory {

	// RulesItem
	
	/**
	 * Queries for a profile or VIP with the matching id
	 * @param context the context of the request
	 * @param id the id to query for
	 * @return the matching profile or VIP
	 * @throws DataEntityDoesNotExistException if data entity does not exist 
	 */
	public IRulesItem GetRulesItemById(Context context, int id) throws DataEntityDoesNotExistException {
		IRulesItem rulesItem = TryGetProfileById(context, id);
		if (rulesItem != null) {
			return rulesItem;
		}
		
		return GetVIPById(context, id);
	}
	
	// Profile
	
	/**
	 * Creates a new profile.
	 * @param name the name of the profile
	 * @param isActive whether the profile is active or not
	 * @param alarmClock the alarm clock of the profile
	 * @param matchingAutoResponse the auto response for matching contacts
	 * @param nonMatchingAutoResponse the auto response for non matching contacts
	 * @return the new profile
	 */
	public IProfile CreateProfile(
		String name, boolean isActive, IAlarmClock alarmClock, IAutoResponse matchingAutoResponse, IAutoResponse nonMatchingAutoResponse) {
		return new Profile(name, isActive, alarmClock, matchingAutoResponse, nonMatchingAutoResponse);
	}
	
	/**
	 * Queries for a profile with the matching id
	 * @param context the context of the request
	 * @param id the id to query for
	 * @return the matching profile.
	 * @throws DataEntityDoesNotExistException if the profile does not exist
	 */
	public IProfile GetProfileById(Context context, int id) throws DataEntityDoesNotExistException {
		return Profile.GetProfileById(context, id);
	}
	
	/**
	 * Queries for a profile with the matching id
	 * @param context the context of the request
	 * @param id the id to query for
	 * @return the matching profile, or null if does not exist.
	 */
	public IProfile TryGetProfileById(Context context, int id) {
		return Profile.TryGetProfileById(context, id);
	}
	
	/**
	 * Queries for a profile with the matching name
	 * @param context the context of the request
	 * @param name the name to query for
	 * @return the matching profile.
	 * @throws DataEntityDoesNotExistException if the profile does not exist
	 */
	public IProfile GetProfileByName(Context context, String name) throws DataEntityDoesNotExistException {
		return Profile.GetProfileByName(context, name);
	}
	
	/**
	 * Queries for a profile with the matching name
	 * @param context the context of the request
	 * @param name the name to query for
	 * @return the matching profile, or null if does not exist.
	 */
	public IProfile TryGetProfileByName(Context context, String name) {
		return Profile.TryGetProfileByName(context, name);
	}
	
	/**
	 * Queries the DB for all profiles including the given contact
	 * @param context the context of the request
	 * @param contact the contact to query
	 * @return a collection of profiles containing the given contact
	 */
	public Set<IProfile> GetProfilesByContact(Context context, IContact contact) {
		return Profile.GetProfilesByContact(context, contact);
	}
	
	/**
	 * Queries the DB for all profiles including time frames matching a time range
	 * @param context the context of the request
	 * @param contact the contact to query
	 * @return a collection of profiles containing the given contact
	 */
	public Set<IProfile> GetProfilesByTimeRange(Context context, TimeInWeek startTime, TimeInWeek endTime) {
		return Profile.GetProfilesByTimeRange(context, startTime, endTime);
	}
	
	/**
	 * Queries the DB for all active profiles
	 * @param context the context of the request
	 * @return all active profiles
	 */
	public Set<IProfile> GetActiveProfiles(Context context) {
		return Profile.GetActiveProfiles(context);
	}
	
	// VIP
	
	/**
	 * Queries for a VIP with the given id
	 * @param context the context of the request
	 * @param id the id to query
	 * @return the VIP with the given id
	 * @throws DataEntityDoesNotExistException if the VIP does not exist
	 */
	public IVIP GetVIPById(Context context, int id) throws DataEntityDoesNotExistException {
		return VIP.GetVIPById(context, id);
	}
	
	/**
	 * Queries for a VIP with the given id
	 * @param context the context of the request
	 * @param id the id to query
	 * @return the VIP with the given id, or null if does not exist
	 */
	public IVIP TryGetVIPById(Context context, int id) {
		return VIP.TryGetVIPById(context, id);
	}
	
	/**
	 * Queries for a VIP with the given contact
	 * @param context the context of the request
	 * @param contact the contact to query
	 * @return the VIP with the given contact
	 * @throws DataEntityDoesNotExistException if the VIP does not exist
	 */
	public IVIP GetVIPByContact(Context context, IContact contact) throws DataEntityDoesNotExistException {
		return VIP.GetVIPByContact(context, contact);
	}
	
	/**
	 * Queries for a VIP with the given contact
	 * @param context the context of the request
	 * @param contact the contact to query
	 * @return the VIP with the given contact, or null if does not exist
	 */
	public IVIP TryGetVIPByContact(Context context, IContact contact) {
		return VIP.TryGetVIPByContact(context, contact);
	}
	
	// IReferencingDataEntityFactory implementation
	
	@Override 
	public Set<IReferencingDataEntity> GetReferencingEntities(Context context, IReferencedDataEntity referencedDataEntity) throws DataEntityDoesNotExistException {
		Set<IReferencingDataEntity> referencingEntities = new HashSet<IReferencingDataEntity>();
		
		if (IContact.class.isInstance(referencedDataEntity)) {
			for (IProfile profile : Profile.GetProfilesByContact(context, (IContact)referencedDataEntity)) {
				referencingEntities.add(profile);
			}
			
			IVIP vipByContact = TryGetVIPByContact(context, (IContact)referencedDataEntity);
			if (vipByContact != null) {
				referencingEntities.add(vipByContact);
			}
		}
		else if (IAlarmClock.class.isInstance(referencedDataEntity)) {
			IRulesItem rulesItem = Profile.TryGetProfileByAlarmClock(context, (IAlarmClock)referencedDataEntity);
			if (rulesItem == null) {
				rulesItem = VIP.GetVIPByAlarmClock(context, (IAlarmClock)referencedDataEntity);
			}
			
			referencingEntities.add(rulesItem);
		}
		else if (IAutoResponse.class.isInstance(referencedDataEntity)) {
			IRulesItem rulesItemByAutoResponse = Profile.TryGetProfileByMatchingAutoReposne(context, (IAutoResponse)referencedDataEntity);
			if (rulesItemByAutoResponse == null) {
				rulesItemByAutoResponse = Profile.GetProfileByNonMatchingAutoResposne(context, (IAutoResponse)referencedDataEntity);
			}
			
			if (rulesItemByAutoResponse == null) {
				rulesItemByAutoResponse = VIP.GetVIPByMatchingAutoResponse(context, (IAutoResponse)referencedDataEntity);
			}
			
			referencingEntities.add(rulesItemByAutoResponse);
		}
		
		else if (ITimeFrame.class.isInstance(referencedDataEntity)) {
			IRulesItem rulesItemByTimeFrame = Profile.GetProfileByTimeFrame(context, (ITimeFrame)referencedDataEntity);
			if (rulesItemByTimeFrame == null) {
				rulesItemByTimeFrame = VIP.GetVIPByTimeFrame(context, (ITimeFrame)referencedDataEntity);
			}
			
			referencingEntities.add(rulesItemByTimeFrame);
		}
		
		return referencingEntities;
	}
}
